home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 428_02 / libsrc / comlib.asm < prev    next >
Encoding:
Assembly Source File  |  1994-03-13  |  10.6 KB  |  377 lines

  1. ;-----------------------------------------------------------------------;
  2. ; COMLIB.ASM    Communication library for C.                ;
  3. ;                                    ;
  4. ; Pictor, Version 1.51, Copyright (c) 1992-94 SoftCircuits.        ;
  5. ; Redistributed by permission.                        ;
  6. ;-----------------------------------------------------------------------;
  7. %    .MODEL    memmodel,c
  8.  
  9.     EXTRN    atexit:PROC
  10.  
  11.     .DATA
  12.     PUBLIC    _PL_comtimeout,_PL_comoverflow
  13. _PL_comtimeout    DW    90        ;Number of 18ths/second before timeout
  14. _PL_comoverflow    DW    0        ;1 if data buffer overflows
  15.  
  16. BUFSIZ        EQU    512        ;Size of serial port data buffer
  17. buffer        DB    BUFSIZ DUP (0)    ;Serial port data buffer
  18. buff_head    DW    OFFSET buffer
  19. buff_tail    DW    OFFSET buffer
  20. buff_count    DW    0        ;Number of bytes in buffer
  21.  
  22. iobase        DW    0        ;Base I/O address for serial port
  23. int_mask    DB    0        ;01h SHL IRQn
  24. int_num        DB    0        ;IRQn + 08h
  25.  
  26. old_handler    DD    0        ;Original interrupt handler
  27. installed_flag    DB    0        ;1 = handler is installed
  28. registered_flag    DB    0        ;1 = registered w/atexit
  29. timer        DW    0        ;Used for time-out countdown
  30.  
  31.  
  32.     .CODE
  33. old1C_handler    DD    0        ;Original timer handler (in code seg)
  34.  
  35. ;-----------------------------------------------------------------------;
  36. ; This procedure becomes the handler for interrupt-driven        ;
  37. ; communications.                            ;
  38. ;                                    ;
  39. ; Usage:    This procedure cannot be called directly from C.    ;
  40. ;-----------------------------------------------------------------------;
  41. IFDEF    ??version            ;Turbo Assembler
  42. int_handler    PROC    FAR
  43. ELSE
  44. int_handler    PROC FAR PRIVATE
  45. ENDIF
  46.     sti
  47.     push    ax
  48.     push    bx
  49.     push    dx
  50.     push    ds
  51.     mov    ax,@Data        ;Set ds = data segment
  52.     mov    ds,ax
  53.     mov    dx,iobase        ;dx = data port address
  54.     in    al,dx            ;Read most-recently recieved byte
  55.     cmp    buff_count,BUFSIZ    ;Is data buffer full?
  56.     jnb    buffer_full        ;Yes, discard character
  57.     mov    bx,buff_tail        ;Else write character to
  58.     mov    [bx],al            ; buffer tail
  59.     inc    buff_tail        ;Bump tail pointer
  60.     cmp    buff_tail,OFFSET buffer+BUFSIZ ;End of buffer?
  61.     jb    char_stuffed        ;No, done
  62.     mov    buff_tail,OFFSET buffer    ;Else wrap pointer to buffer start
  63. char_stuffed:
  64.     inc    buff_count        ;Increment counter
  65. end_int_handler:
  66.     mov    al,20h            ;Send end-of-interrupt to 8259
  67.     out    20h,al
  68.     pop    ds
  69.     pop    dx
  70.     pop    bx
  71.     pop    ax
  72.     iret
  73. buffer_full:
  74.     mov    _PL_comoverflow,1        ;Set overflow flag
  75.     jmp    end_int_handler
  76. int_handler    ENDP
  77.  
  78. ;-----------------------------------------------------------------------;
  79. ; Timer interrupt handler. Decrements timer if timer is non-zero and    ;
  80. ; chains to original timer handler.                    ;
  81. ;                                    ;
  82. ; Usage:    This procedure cannot be called directly from C.    ;
  83. ;-----------------------------------------------------------------------;
  84. IFDEF    ??version            ;Turbo Assembler
  85. int1C_handler    PROC    FAR
  86. ELSE
  87. int1C_handler    PROC FAR PRIVATE
  88. ENDIF
  89.     sti
  90.     push    ax
  91.     push    ds
  92.     mov    ax,@Data        ;Set ds = data segment
  93.     mov    ds,ax
  94.     cmp    timer,0            ;Are we counting down?
  95.     je    end_int1C_handler    ;No, get out
  96.     dec    timer            ;Else decrement timer
  97. end_int1C_handler:
  98.     pop    ds
  99.     pop    ax
  100.     cli                ;Handler expects interrupts off
  101.     jmp    cs:old1C_handler    ;Chain to previous handler
  102. int1C_handler    ENDP
  103.  
  104.     PUBLIC    comloc
  105. ;-----------------------------------------------------------------------;
  106. ; Returns the number of characters waiting in the receive data buffer.    ;
  107. ;                                    ;
  108. ; Usage:    int comloc(void);                    ;
  109. ;-----------------------------------------------------------------------;
  110. comloc        PROC
  111.     mov    ax,buff_count        ;Return number of bytes in
  112.     ret                ; buffer in ax
  113. comloc        ENDP
  114.  
  115.     PUBLIC    comflush
  116. ;-----------------------------------------------------------------------;
  117. ; Clears any characters waiting in the receive data buffer and clears    ;
  118. ; any error conditions.                            ;
  119. ;                                    ;
  120. ; Usage:    int comflush(void);                    ;
  121. ; Returns:    The number of characters flushed from the buffer.    ;
  122. ;-----------------------------------------------------------------------;
  123. comflush    PROC
  124.     mov    ax,buff_count        ;Return number of character in buffer
  125.     mov    buff_head,OFFSET buffer    ;Reset buffer pointers
  126.     mov    buff_tail,OFFSET buffer
  127.     mov    buff_count,0
  128.     mov    _PL_comoverflow,0    ;Clear overflow flag
  129.     ret
  130. comflush    ENDP
  131.  
  132.     PUBLIC    comclose
  133. ;-----------------------------------------------------------------------;
  134. ; Removes communications interrupt handlers and flushes buffers.    ;
  135. ;                                    ;
  136. ; Usage:    int comclose(void);                    ;
  137. ; Returns:    0 = success, -1 = error                    ;
  138. ;-----------------------------------------------------------------------;
  139. comclose    PROC
  140.     mov    ax,-1
  141.     cmp    installed_flag,0    ;Are our routines installed?
  142.     je    end_comclose        ;No, ignore request
  143.     in    al,21h            ;Read current 8259 mask
  144.     or    al,int_mask        ;Mask out interrupt
  145.     out    21h,al            ;Write it back
  146.     mov    ah,25h            ;Restore communications handler
  147.     mov    al,int_num
  148.     push    ds
  149.     lds    dx,old_handler
  150.     int    21h
  151.     pop    ds
  152.     mov    ax,251Ch        ;Restore timer handler
  153.     push    ds
  154.     lds    dx,cs:old1C_handler
  155.     int    21h
  156.     pop    ds            ;Restore ds
  157.     call    comflush        ;Flush receive buffer and
  158.     mov    timer,0            ; reset timer
  159.     mov    installed_flag,0
  160.     sub    ax,ax
  161. end_comclose:
  162.     ret
  163. comclose    ENDP
  164.  
  165. ;-----------------------------------------------------------------------;
  166. ; Installs our interrupt vectors and programs the UART.            ;
  167. ;                                    ;
  168. ; Usage:    This procedure cannot be called directly from C.    ;
  169. ;-----------------------------------------------------------------------;
  170. IFDEF    ??version            ;Turbo Assembler
  171. install_handler    PROC    NEAR
  172. ELSE
  173. install_handler    PROC NEAR PRIVATE
  174. ENDIF
  175.     push    ax
  176.     push    bx
  177.     push    dx
  178.     push    es
  179.     mov    ah,35h            ;Save old interrupt vector
  180.     mov    al,int_num
  181.     int    21h
  182.     mov    WORD PTR old_handler[0],bx
  183.     mov    WORD PTR old_handler[2],es
  184.     push    ds            ;Set new interrupt vector
  185.     mov    ah,25h
  186.     mov    al,int_num
  187.     push    cs
  188.     pop    ds
  189.     mov    dx,OFFSET int_handler
  190.     int    21h
  191.     pop    ds
  192.     mov    ax,351Ch        ;Get old timer interrupt vector
  193.     int    21h
  194.     mov    WORD PTR cs:old1C_handler[0],bx
  195.     mov    WORD PTR cs:old1C_handler[2],es
  196.     push    ds            ;Set new timer interrupt vector
  197.     mov    ax,251Ch
  198.     push    cs
  199.     pop    ds
  200.     mov    dx,OFFSET int1C_handler
  201.     int    21h
  202.     pop    ds
  203.     mov    dx,iobase        ;Set modem control register
  204.     add    dx,04h            ; DTR, RTS and OUT2 bits
  205.     mov    al,0Bh
  206.     out    dx,al
  207.     mov    dx,iobase        ;Set interrupt enable register
  208.     add    dx,01h            ; to interrupt on data received
  209.     mov    al,01h
  210.     out    dx,al
  211.     mov    dl,int_mask        ;Program 8259 to enable our IRQ
  212.     not    dl
  213.     in    al,21h
  214.     and    al,dl
  215.     out    21h,al
  216.     pop    es
  217.     pop    dx
  218.     pop    bx
  219.     pop    ax
  220.     ret
  221. install_handler    ENDP
  222.  
  223.     PUBLIC    comopen
  224. ;-----------------------------------------------------------------------;
  225. ; Initializes the communications port and installs our own interrupt    ;
  226. ; handlers.                                ;
  227. ;                                    ;
  228. ; Usage:    int comopen(int com_port,int baud_rate,int parity,    ;
  229. ;            int data_bits,int stop_bits,int irq_num);    ;
  230. ; Returns:    0 = success, -1 = com port not found            ;
  231. ;-----------------------------------------------------------------------;
  232. comopen        PROC com_port:WORD,baud_rate:WORD,parity:WORD,\
  233.         data_bits:WORD,stop_bits:WORD,irq_num:WORD
  234.     mov    ax,-1
  235.     cmp    installed_flag,1    ;Are we already installed?
  236.     jne    not_installed        ;No, continue
  237.     jmp    end_comopen        ;Else ignore request
  238. not_installed:
  239.     cmp    irq_num,0        ;Was IRQ specified?
  240.     jne    irq_ready        ;Yes, leave it alone
  241.     mov    irq_num,04h        ;Else set IRQ4 if COM1 or COM3,
  242.     mov    ax,com_port        ;         IRQ3 if COM2 or COM4
  243.     and    ax,0001h
  244.     sub    irq_num,ax
  245. irq_ready:
  246.     mov    cx,irq_num        ;Calculate and save interrupt
  247.     mov    al,01h            ; mask value
  248.     shl    al,cl
  249.     mov    int_mask,al
  250.     add    cl,08h            ;Calculate and save software
  251.     mov    int_num,cl        ; interrupt number
  252.     mov    ax,0040h        ;Get base address for selected
  253.     mov    es,ax            ; com port from ROM BIOS
  254.     mov    bx,com_port
  255.     shl    bx,1
  256.     mov    dx,es:[bx]
  257.     mov    ax,-1            ;Return -1 if port invalid
  258.     cmp    dx,0
  259.     je    end_comopen
  260.     mov    iobase,dx        ;Else save port base I/O address
  261.     add    dx,03h            ;Set bit 7 of line control register
  262.     mov    al,80h            ; and set baud rate
  263.     out    dx,al
  264.     jmp    $+2
  265.     mov    dx,iobase
  266.     mov    ax,baud_rate
  267.     out    dx,al            ;Write low byte of baud rate divisor
  268.     jmp    $+2
  269.     inc    dx
  270.     mov    al,ah
  271.     out    dx,al            ;Write high byte of baud rate divisor
  272.     mov    dx,iobase        ;Initialize line control register
  273.     add    dx,03h
  274.     mov    ax,data_bits
  275.     or    ax,stop_bits
  276.     or    ax,parity
  277.     out    dx,al
  278.     mov    timer,0            ;Reset timer and receive buffer
  279.     call    comflush
  280.     call    install_handler        ;Install our handlers
  281.     mov    installed_flag,1    ;Indicate we're installed
  282.     sub    ax,ax            ;Prepare to return success
  283.     cmp    registered_flag,1    ;Have we registered with atexit()?
  284.     je    end_comopen        ;Yes, done
  285.     mov    registered_flag,1
  286.     IF    @CodeSize        ;Else register comclose with atexit()
  287.     push    cs
  288.     ENDIF
  289.     mov    ax,OFFSET comclose
  290.     push    ax
  291.     call    atexit
  292.     IF    @CodeSize
  293.     add    sp,4
  294.     ELSE
  295.     inc    sp
  296.     inc    sp
  297.     ENDIF
  298.     cmp    ax,0            ;Done if atexit succeeded
  299.     je    end_comopen
  300.     call    comclose        ;Else uninstall ourselves
  301.     mov    registered_flag,0
  302.     mov    ax,-1            ;Return error
  303. end_comopen:
  304.     ret
  305. comopen        ENDP
  306.  
  307.     PUBLIC    comgetc
  308. ;-----------------------------------------------------------------------;
  309. ; Receives one character from the serial port.                ;
  310. ;                                    ;
  311. ; Usage:    int comgetc(char *value);                ;
  312. ; Returns:    0 = success; -1 = error                    ;
  313. ;-----------------------------------------------------------------------;
  314. comgetc        PROC value:PTR BYTE
  315.     mov    ax,-1            ;Return error if handler is
  316.     cmp    installed_flag,0    ; not installed
  317.     je    end_comgetc
  318.     mov    ax,_PL_comtimeout    ;Start timer
  319.     mov    timer,ax
  320. comgetc_wait:
  321.     mov    ax,-1            ;Return -1 if we timed-out
  322.     cmp    timer,0
  323.     je    end_comgetc
  324.     cmp    buff_count,0        ;Anything in receive buffer?
  325.     je    comgetc_wait        ;No, keep waiting
  326.     mov    bx,buff_head        ;Use bx to access buffer
  327.     mov    al,[bx]            ;Get next byte in al
  328.     inc    buff_head        ;Bump pointer
  329.     cmp    buff_head,OFFSET buffer+BUFSIZ    ;End of buffer?
  330.     jb    got_char        ;No, done
  331.     mov    buff_head,OFFSET buffer    ;Else wrap pointer to buffer start
  332. got_char:
  333.     dec    buff_count        ;Adjust count
  334.     IF    @DataSize
  335.     les    bx,value        ;Write value to user variable
  336.     mov    es:[bx],al
  337.     ELSE
  338.     mov    bx,value
  339.     mov    [bx],al
  340.     ENDIF
  341.     sub    ax,ax            ;Return 0
  342. end_comgetc:
  343.     ret
  344. comgetc        ENDP
  345.  
  346.     PUBLIC    computc
  347. ;-----------------------------------------------------------------------;
  348. ; Sends one character out the serial port.                ;
  349. ;                                    ;
  350. ; Usage:    int computc(char value);                ;
  351. ; Returns:    0 = success; -1 = error                    ;
  352. ;-----------------------------------------------------------------------;
  353. computc        PROC value:BYTE
  354.     mov    ax,-1            ;Return error if handler is
  355.     cmp    installed_flag,0    ; not installed
  356.     je    end_computc
  357.     mov    dx,iobase        ;dx = line status register address
  358.     add    dx,5
  359.     mov    ax,_PL_comtimeout    ;Start timer
  360.     mov    timer,ax
  361. computc_wait:
  362.     mov    ax,-1            ;Return -1 if we timed-out
  363.     cmp    timer,0
  364.     je    end_computc
  365.     in    al,dx            ;Read line status register
  366.     test    al,20h            ;Ready for data?
  367.     jz    computc_wait        ;No, keep waiting
  368.     mov    dx,iobase        ;Write character to transmit
  369.     mov    al,value        ; holding register
  370.     out    dx,al
  371.     sub    ax,ax            ;Return 0
  372. end_computc:
  373.     ret
  374. computc        ENDP
  375.  
  376.     END
  377.